#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <stdlib.h>
#include <netdb.h>



#define BUF_SIZE        1024
#define MSG_STR "Hello Server, I connecting..."

void print_usage(const char *program_name)
{

	        printf("\n%s -- 1.0.0(2018.11.20)\n", program_name);		                                        
		printf(" Usage:(1) %s -i <server_ip> -p <server_port>  [-h <server_use_help>]\n", program_name);
		printf("       (2) %s -n <server_hostname> -p <server_port>  [-h <server_use_help>]\n", program_name);
		printf("        -i --ip         the server ip_address you want to connect\n") ;
		printf("        -p --port       the server listen port you want to connect\n") ;
		printf("        -n --hostname   the server hostname you want to connect\n") ;
	        printf("        -h --help       the client file how to use\n");
	        printf("        Notice: If use hostname to connect Server ,Information get Segmentation fault, Please check out the hostname is ture you input!\n");

	        return ;
}



int main(int argc, char** argv)
{
        int     conn_fd ;
        struct  sockaddr_in serv_addr ;
        char    buf[BUF_SIZE] ;
        char    send_buf[32] ;
        int     rv = -1 ;
	int     opt = -1 ;
        int     port = 0 ;
        char*   ip = NULL ;
        char*   hostname = NULL;

        struct hostent *hostnp;


        const char *short_opts = "n:i:p:h";

        const struct option long_opts[] =       {
                                                       {"help", no_argument, NULL, 'h'},
						       {"hostname", required_argument,NULL,'n'},

						       {"port", required_argument, NULL, 'p'},

						       {"ip", required_argument, NULL, 'i'},

						       {0, 0, 0, 0},

						};



	while ((opt= getopt_long(argc, argv, short_opts, long_opts,NULL)) != -1)
	
	{
	
		switch (opt)
																					                               
		{
			case 'p':
				port = atoi(optarg);
				break ;
			
			case 'i':																																								                                             
				ip = optarg ;
				break ;
																																																		        			case 'n':	
				hostname = optarg ;
				break ;

																																																						case 'h':				
				print_usage(argv[0]) ;
				return 0;
		
		}
		
	}


	if( ( ( !port) || (!hostname) ) && ( (!ip) || (!port) )  )
	{    
																		                
		print_usage(argv[0]);
		return 0;


	}

							
	memset(buf, 0, sizeof(buf)) ;

																  
  	if ( hostname )																		        
	{
		
	if( (hostnp = gethostbyname(hostname) ) == NULL )
	{
		printf("get host by name failure: %s\n", strerror(h_errno)) ;
		return 0 ;
	
	}

		printf("hostname %s\n", hostnp->h_name);


		ip = inet_ntoa( * (struct in_addr *)hostnp->h_addr );

		printf("addr:%s\n",ip) ;

	}



	conn_fd = socket( AF_INET, SOCK_STREAM, 0 ) ;


	if(conn_fd < 0)
	{
		
		printf("creat socket failure : %s\n", strerror(errno)) ;
		return -1 ;
	}
	
	printf("socket suceeful,connect file descriptor[%d]\n" ,conn_fd) ;
	memset(&serv_addr, 0, sizeof(serv_addr)) ;
	serv_addr.sin_port = htons(port) ;
	serv_addr.sin_family = AF_INET ;
	inet_aton(ip, &serv_addr.sin_addr);


	if( connect(conn_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0 )
	{
		printf("connect failure[%s:%d] : %s\n",  inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port), strerror(errno)) ;
		goto cleanup ;

	}

	printf("connect server[%s:%d] succeful!\n",  inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)) ;


	memset(buf, 0, sizeof(buf)) ;

	rv = read(conn_fd, buf, sizeof(buf)) ;

	if(rv < 0)
	{
		printf("read from server failed: %s\n", strerror(errno)) ;
		goto cleanup ;
	}
	if(rv == 0)
	{
			printf("disconnect with server!\n") ;
	}


	printf("Server Usage: %s\n", buf) ;
	
	while(1)
	{
		
		scanf("%s", send_buf) ;
	
		if(write(conn_fd, send_buf, strlen(send_buf)) < 0 )																{
			printf("Write to server failed: %s\n", strerror(errno)) ;
			goto cleanup ;
		}
					
		
		memset(buf, 0, sizeof(buf)) ;
		rv = read(conn_fd, buf, sizeof(buf)) ;
		if(rv < 0)		
		{				
			printf("read from server failed: %s\n", strerror(errno)) ;
			goto cleanup ;
		}
		if(rv == 0)
		{
			printf("disconnect with server!\n") ;
			goto cleanup ;
		}

		printf("read %d byte from server:' %s'\n", rv, buf) ;																																																		      
		if( strcmp(send_buf, "quit") == 0)
		{
			break ;
		}


       	} 

		printf("close conn_fd[%d],and  client exit!\n", conn_fd) ;



cleanup:
	close(conn_fd) ;

	
	return 0 ;
}
